/**
 * 
 */
package server;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.apache.log4j.Logger;

import server.alarmThreads.AlarmDbUpdateThread;
import server.alarmThreads.AlarmThread;
import server.alarmThreads.LocalAlarmThread;
import server.alarmThreads.NotifryThread;
import server.alarmThreads.OnlineCheckerThread;
import server.alarmThreads.ProwlThread;
import server.alarmThreads.SMSVersandThread;
import server.config.ServerConfig;
import server.container.Blocker;
import server.container.EinsatzAlarm;
import server.container.SMSAlamierung;
import server.db.SQL;

/**
 * @author Christian
 * 
 */
public class ServerAlarmAppController implements Runnable {

	private ConcurrentLinkedQueue<EinsatzAlarm> list;

	private List<SMSAlamierung> smsAlarmList = Collections
			.synchronizedList(new ArrayList<SMSAlamierung>());

	private List<AlarmThread> alarmThreads = new ArrayList<AlarmThread>();

	private Map<String, Blocker> blockermap = new HashMap<String, Blocker>();

	private static Logger logger = Logger.getLogger(ServerAlarmAppController.class);
	
	private AlarmDbUpdateThread dbLogThread = null;

	public ServerAlarmAppController(ConcurrentLinkedQueue<EinsatzAlarm> list) {

		this.list = list;
		initThreads();
	}

	/**
	 * @see java.lang.Runnable#run()
	 */
	@Override
	public void run() {

		logger.trace("Controllerrunmethode");
		while (true) {
			synchronized (list) {
				try {
					if (list.isEmpty()) {
						cleanUpBlockerMap();
						System.gc();
						list.wait();
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			//isalive aufrecherhalten
			OnlineCheckerThread.getInstance().updateLastAlarm();
			
			//Alarmverarbeitung
			if (!list.isEmpty()) {
				long t1 = System.nanoTime();
				EinsatzAlarm alarm = list.peek();
				if (alarm.getAlarmKennung().equals("0576000") || alarm.getAlarmKennung().equals("0846008")) {
					synchronized (list) {

						list.remove(alarm);
					}
					SQL.getInstance().getConPool().connectionOk();
					continue;
				}
//				if(alarm.isPocsag()) {
//					synchronized (list) {
//
//						list.remove(alarm);
//					}
//					continue;
//				}
				//asyncron DB eintrag erstellen
				if(!alarm.isWritenToDB()) {
					dbLogThread.alarmiere(alarm);
					alarm.setWritenToDB(true);
				}
				
				if (alarm.is5Ton() && alarm.istFMSFeuerwehr()) {
					if (alarm.getAlarmTime() + 35000 > System.currentTimeMillis()) {
						list.remove(alarm);
						list.add(alarm);
						sleep(100);
						
						continue;
					}
				}
				// Blocker für 5-ton Wehren verkürzen
				if (!alarm.istFMSFeuerwehr() && !alarm.is5Ton() && !alarm.isPocsag()) {
					SQL.setIstFMSFeuerwehr(alarm.getFeuerwehrID());
				}
				if (!isBlocked(alarm)) {

					alarmiereAlleAlarmThreads(alarm);

					// Nummer für den Alarm holen
					List<SMSAlamierung> nummern = SQL.getInstance().getSMSAlarmList(alarm);
					if (nummern.size() == 0) {
						logger.info("Keine Nummern für diese Schleife eingetragen!  "
								+ alarm.getSchleife());
					}
					synchronized (smsAlarmList) {
						for (SMSAlamierung smsalarm : nummern) {
							smsAlarmList.add(smsalarm);
						}
						smsAlarmList.notifyAll();
					}
					long blockzeit = System.currentTimeMillis() + (1000 * 60 * 30);
										
					blockermap.put(alarm.getBlockIdentifier(), new Blocker(alarm.getSchleife(),
							blockzeit, false, !alarm.is5Ton()));
					if (alarm.getSchleife().equals("00-00")) {
						for (String schleife : SQL.getAlleFeuerwehrIDs()) {
							long blockzeitProbe = System.currentTimeMillis() + (1000 * 60 * 15);
							blockermap.put(schleife, new Blocker(schleife, blockzeitProbe,
									true, !alarm.is5Ton()));
						}
					}
					
				}
				list.remove(alarm);
				long t2 = System.nanoTime();
				System.out.println("zeit:" + (t2 - t1) / 1000);
			}
		}
	}

	private void alarmiereAlleAlarmThreads(EinsatzAlarm alarm) {

		for (AlarmThread t : alarmThreads) {

			t.alarmiere(alarm);
		}
	}

	private boolean isBlocked(EinsatzAlarm alarm) {

		// Alarme ohne feuerwehr können nicht ausgeführt werden.
		if (alarm.getFeuerwehrID() == -1) {

			return true;
		}

		if (!blockermap.containsKey(alarm.getBlockIdentifier())) {
			return false;
		}
		Blocker b = blockermap.get(alarm.getBlockIdentifier());
		if (b.getBlockenbis() < System.currentTimeMillis()
				|| (b.isProbeAlarm() && !alarm.is5Ton() && !alarm.isProbeAlarm())
				|| (b.is5Ton() && !alarm.is5Ton() && !alarm.isProbeAlarm())) {
			return false;
		}
		return true;
	}

	private void cleanUpBlockerMap() {
	
		String[] array = blockermap.keySet().toArray(new String[1]);
		
		for(int i = 0;i < array.length;i++) {
			
			if(array[i] != null) {			
				if (blockermap.get(array[i]) != null && blockermap.get(array[i]).getBlockenbis() < System.currentTimeMillis()) {
					blockermap.remove(array[i]);
					i--;
				}
			}
		}	
	}

	private void initThreads() {

		dbLogThread = new AlarmDbUpdateThread();
		initSMSThreads();
		alarmThreads.add(new ProwlThread());
		alarmThreads.add(new NotifryThread());
		alarmThreads.add(new LocalAlarmThread());
	}

	private void initSMSThreads() {

		logger.trace("Start SMS Threads");
		int anzahlThreads = ServerConfig.getInstance().getSmsThreadsAnzahl();
		for (int i = 0; i < anzahlThreads; i++) {
			new Thread(new SMSVersandThread(smsAlarmList)).start();
		}
		logger.info(anzahlThreads + " SMS Threads gestartet");
	}

	/**
	 * 
	 * @param sleep
	 *            Sleep
	 */
	private void sleep(long sleep) {

		try {
			Thread.sleep(sleep);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
